home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 2 / Gold Medal Software Volume 2 (Gold Medal) (1994).iso / prog / adlip.arj / CONVERT.C < prev    next >
C/C++ Source or Header  |  1988-10-14  |  23KB  |  1,066 lines

  1. /*
  2.     CONVERT.C
  3.  
  4.     27-jun-88, Marc Savary, Ad Lib Inc.
  5.  
  6.     Module to convert *.ROL file to AdLib Midi file, *.MUS & *.SND
  7.  
  8.     The beginning of the .MUS file contains 70 bytes
  9.     of start-up information (see convert.h file):
  10.         1:      major version # of file
  11.         1:      minor version # of file
  12.         4:    melody identification
  13.         30:    melody name
  14.         1:      ticks per beat
  15.         1:      beats per measure
  16.         4:    length of melody, in ticks
  17.         4:    length of melody's data part
  18.         4:    total number of commands in melody, including NOTE-ON, NOTE-OFF,
  19.             PROGRAM-CHANGE, AFTER-TOUCH, PITCH-BEND, OVERFLOW, SYSTEM-XOR
  20.             & STOP
  21.         8:    filler area, set to zero
  22.         1:    sound mode: 0 == melodic, 1 == percussive
  23.         1:  pitch bend range, from 1 to 12
  24.         2:    basic tempo
  25.         8:    filler area, set to zero
  26.  
  27.     Following the header is the musical data.
  28.     The data part of the .MUS file contains midi 1.0 commands with timing
  29.     bytes of 1/tickBeat. tickBeat is the number of divisions per beat.
  30.     The relation between tickBeat, tempo (beat per minute) & frequency of
  31.     the timing counter is:
  32.         frequency = (tempo / 60) * tickBeat.
  33.         
  34.     Timing bytes vary from 0 to 0xFE and precede every command. A timing
  35.     byte of 0xF8 means timing overflow with a value of 240. An overflow
  36.     byte is always followed by another overflow byte or timing byte.
  37.  
  38.     Program changes refer to timbre definitions in the .SND bank file by their
  39.     relative order. While converting files, if a timbre ( ref. by it's name)
  40.     is not found in the bank file, its definition is appended to the end.
  41.  
  42.     A tempo change is specified within a SYSTEM EXCLUSIVE MESSAGE:
  43.     0xF0 0x7F 00 <integer> <frac> 0xF7, where 'integer' is the integer
  44.     part of the tempo multiplier and 'frac' the fractionnal part, in 1/128.
  45.  
  46.     Each voice is associated with one midi channel. In melodic mode,
  47.     channels 0 to 8 are melodic; in percussive mode, channels 0 to 5
  48.     are melodic and channels 6 to 11 are percussive.
  49.  
  50.     The last MIDI command of the file is STOP ( 0xFC).
  51.  
  52.     If compiling with Lattice, 'LATTICE' must be defined for MEMORY.C
  53.     and BANK.C.
  54.  
  55.     With Microsoft, use the following ('MICROSOFT' must be defined for
  56.     this file and BANK.C):
  57.       cl -DMICROSOFT -AS -J -Zi /Zp1 -Ox -Gs play.c bank.c adlib.c
  58.  
  59. */
  60.  
  61. #include "mem.h"
  62. #include "convert.h"
  63. #include "adlib.h"
  64. #include "bank.h"
  65. #include "strmidi.h"
  66.  
  67. #include "fcntl.h"
  68. #include "stdio.h"
  69.  
  70. #ifdef MICROSOFT
  71. #include <sys\types.h>
  72. #include <sys\stat.h>
  73. #define  open(x,y)      open(x,y,S_IWRITE)
  74. #define  setmem(x,y,z)  memset(x,z,y)
  75. #define  min(x,y)       ((x < y) ? x:y)
  76. #define  max(x,y)       ((x > y) ? x:y)
  77. #endif
  78.  
  79. #define NR_MELO_VOICES 9        /* in melodic mode */
  80. #define NR_PERC_VOICES 11        /* in percussive mode */
  81.  
  82. #define BLOCK_SIZE 512            /* must be power of two !!! */
  83. #define instrumFileExtension ".INS"
  84. #define musicFileExtension ".ROL"
  85.  
  86. #define MAJOR_VERSION    1
  87. #define MINOR_VERSION    0
  88.  
  89. /* type of events, decreasing in order of priority: */
  90. #define NOTE_OFF_TP    0
  91. #define PRESET_TP        1
  92. #define PITCH_TP        2
  93. #define VOLUME_TP        3
  94. #define TEMPO_TP        4
  95. #define NOTE_ON_TP        5
  96. #define NR_TYPES        6
  97.  
  98.  
  99.  
  100. typedef int Time;
  101.  
  102. typedef
  103.     struct {
  104.         unsigned nrBytes;
  105.         unsigned size;
  106.         Handle liste;
  107.     } ListDesc;
  108.  
  109. typedef
  110.     struct {
  111.         Time    time;
  112.         float    tempo;
  113.     } TempoEvent;
  114.  
  115. typedef
  116.     struct {
  117.         int        note;
  118.         int        duree;
  119.     } NoteEvent;
  120.  
  121.  
  122. typedef
  123.     struct {
  124.         Time time;
  125.         char instrumName[ 9];
  126.         char filler;
  127.         int    timbreIndex;
  128.     } InstrumEvent;
  129.  
  130. typedef
  131.     struct {
  132.         Time time;
  133.         float volume;
  134.     } VolumeEvent;
  135.  
  136.  
  137. typedef
  138.     struct {
  139.         Time time;
  140.         float pitch;
  141.     } PitchEvent;
  142.  
  143. typedef
  144.     struct {
  145.         char instrumName[ 9];
  146.         int    params[ 26];
  147.     } TimbreDef;
  148.  
  149. typedef
  150.     struct {
  151.         long    rollTime;
  152.         long    rollPos;
  153.         char    voice;
  154.         char    used;
  155.         char    type;
  156.     } Cedule;
  157.  
  158. #define NoteAtPos( vc, pos) ((NoteEvent *) *noteList[ vc].liste + pos)
  159. #define PitchAtPos( vc, pos) ((PitchEvent *) *pitchList[ vc].liste + pos)
  160. #define VolumeAtPos( vc, pos) ((VolumeEvent *) *volumeList[ vc].liste + pos)
  161. #define InstrumAtPos( vc, pos) ((InstrumEvent *) *instrumList[ vc].liste + pos)
  162. #define TempoAtPos( pos) ((TempoEvent *) *tempoList.liste + pos)
  163.  
  164. #define PitchSize( vc) ( pitchList[ vc].size)
  165. #define InstrumSize( vc) ( instrumList[ vc].size)
  166. #define VolumeSize( vc) ( volumeList[ vc].size)
  167. #define TempoSize() ( tempoList.size)
  168. #define NoteSize( vc) ( noteList[ vc].size)
  169.  
  170. ListDesc    instrumList[ NR_VOICES];
  171. ListDesc    noteList[ NR_VOICES];
  172. ListDesc    pitchList[ NR_VOICES];
  173. ListDesc    volumeList[ NR_VOICES];
  174. ListDesc    tempoList;
  175. ListDesc    timbreList;
  176. int        srcTickBeat,
  177.             destTickBeat;
  178. int        beatMeasure;
  179. char        notPercusMode;
  180. float        basicTempo;
  181. int        pitchBRange;
  182. Time        duree_piece;    /* length of piece */
  183.  
  184. Cedule        cedList[ NR_TYPES][ NR_VOICES];
  185. long        offTime[ NR_VOICES];
  186. long        mpuTime;
  187. char        statusArray[ NR_TYPES] = { NOTE_ON_BYTE, PROG_CHANGE_BYTE,
  188.                                     PITCH_BEND_BYTE, AFTER_TOUCH_BYTE,
  189.                                     00, NOTE_ON_BYTE };
  190. char        status;
  191. long        byteCount;
  192. long        commCount;
  193. char        voiceVolume[ NR_VOICES];
  194. int        outFile;
  195. BankPtr     timbBank;
  196.  
  197. extern long    ConvertTime();
  198.  
  199.  
  200.  
  201.  
  202. main( argc, argv)
  203.     int argc;
  204.     char * argv[];
  205. {
  206.     char buff[ 150];
  207.  
  208.     if( argc < 4) {
  209.         fprintf( stderr, "\nUSE: convert <infile.rol> <bankfile.tim> <outfile.mus>");
  210.         exit( 1);
  211.         }
  212.  
  213.     InitMemory( 32);
  214.     ColdInit();
  215.  
  216.     timbBank = OpenBank( argv[ 2], 1);
  217.     if( NULL == timbBank) {
  218.         fprintf( stderr, "\nCannot open timbre bank file '%s'.", argv[ 2]);
  219.         exit( 1);
  220.         }
  221.  
  222.     outFile = open( argv[ 3], O_WRONLY + O_RAW + O_TRUNC + O_CREAT);
  223.     if( -1 == outFile) {
  224.         fprintf( stderr, "\nUnable to open write file '%s'.", argv[ 3]);
  225.         exit( 1);
  226.         }
  227.  
  228.     if( !ConvertFile( argv[ 1])) {
  229.         fprintf( stderr, "\nUnable to open read file '%s'.", argv[ 1]);
  230.         exit( 1);
  231.         }
  232.     close( outFile);
  233.     CloseBank( timbBank);
  234. }    /* main() */
  235.         
  236.  
  237.  
  238.  
  239. ColdInit()
  240. {
  241.     int i;
  242.  
  243.     for( i = 0; i < NR_VOICES; i++) {
  244.         instrumList[ i].size = 0;
  245.         instrumList[ i].liste = NewHandle( (Size) 4);
  246.         instrumList[ i].nrBytes = 4;
  247.  
  248.         noteList[ i].size = 0;
  249.         noteList[ i].liste = NewHandle( (Size) 4);
  250.         noteList[ i].nrBytes = 4;
  251.  
  252.         pitchList[ i].size = 0;
  253.         pitchList[ i].liste = NewHandle( (Size) 4);
  254.         pitchList[ i].nrBytes = 4;
  255.  
  256.         volumeList[ i].size = 0;
  257.         volumeList[ i].liste = NewHandle( (Size) 4);
  258.         volumeList[ i].nrBytes = 4;
  259.         }
  260.     tempoList.size = 0;
  261.     tempoList.liste = NewHandle( (Size) 4);
  262.     tempoList.nrBytes = 4;
  263.  
  264.     timbreList.size = 0;
  265.     timbreList.liste = NewHandle( (Size) 4);
  266.     timbreList.nrBytes = 4;
  267.  
  268.     /* Set the number of ticks per beat of the resulting conversion
  269.     ( must be a multiple of the ticks/beat of the .ROL file)
  270.     This value is used for the conversion of the timing base. */
  271.     destTickBeat = DEFAULT_TICK_BEAT;
  272. }    /* ColdInit() */
  273.  
  274.  
  275.  
  276. /*
  277.     For doing conversion, we first load the piece, and simulate
  278.     the playing for ordering the events, using priority values when
  279.     the events occur at the same time.
  280. */
  281. int ConvertFile( fileName)
  282.     char * fileName;
  283. {
  284.  
  285.     int     voix, nb_voices;
  286.     Time    longueur;
  287.     Cedule * ced;
  288.     struct MusHeader mHd;
  289.     extern Cedule * NextCedule();
  290.  
  291.     if( ! MyLoadMelo( fileName))
  292.         return 0;
  293.     LoadTimbres();
  294.  
  295.     setmem( &mHd, sizeof( struct MusHeader), 0);
  296.     write( outFile, &mHd, sizeof( struct MusHeader));
  297.  
  298.     StartCedule();
  299.  
  300.     while( ced = NextCedule()) {
  301.         switch( ced->type) {
  302.             case PRESET_TP:    DoPreset( ced);    break;
  303.             case PITCH_TP:    DoPitch( ced);    break;
  304.             case VOLUME_TP:    DoVolume( ced);    break;
  305.             case TEMPO_TP:    DoTempo( ced);    break;
  306.             case NOTE_ON_TP:    DoNoteOn( ced);    break;
  307.             case NOTE_OFF_TP:    DoNoteOff( ced);    break;
  308.             default:        printf( "\nBad event type: %d", ced->type);
  309.             }
  310.         }
  311.     DoEndMelo();
  312.  
  313.     mHd.majorVersion = MAJOR_VERSION;
  314.     mHd.minorVersion = MINOR_VERSION;
  315.     mHd.tickBeat = destTickBeat;
  316.     mHd.beatMeasure = beatMeasure;
  317.     mHd.totalTick = ConvertTime( duree_piece);
  318.     mHd.dataSize = byteCount;
  319.     mHd.nrCommand = commCount;
  320.     mHd.soundMode = !notPercusMode;
  321.     mHd.pitchBRange = pitchBRange;
  322.     mHd.basicTempo = basicTempo;
  323.  
  324.     /* write header to output file: */
  325.     lseek( outFile, 0L, 0);
  326.     write( outFile, &mHd, sizeof( struct MusHeader));
  327. }    /* ConvertFile() */
  328.  
  329.  
  330.  
  331. /*
  332.     Start the simulation of playing a melody.
  333. */
  334. StartCedule()
  335.     {
  336.     int i, j, k;
  337.     Cedule * ced;
  338.  
  339.     ced = &cedList[ 0][ 0];
  340.     for( i = 0; i < NR_TYPES; i++)
  341.         for( k = 0; k < NR_VOICES; k++, ced++) {
  342.             ced->rollTime = 0;
  343.             ced->rollPos = 0;
  344.             ced->used = 0;
  345.             ced->voice = k;
  346.             ced->type = i;
  347.             }
  348.     for( k = 0; k < NR_VOICES; k++) {
  349.         CedulePreset( k, 0);
  350.         CedulePitch( k, 0);
  351.         CeduleVolume( k, 0);
  352.         offTime[ k] = 0;
  353.         CeduleNoteOn( k, 0);
  354.         }
  355.     CeduleTempo( 0);
  356.     mpuTime = 0;
  357.     status = 0;
  358.     byteCount = 0;
  359.     commCount = 0;
  360.     }    /* StartCedule() */
  361.  
  362.  
  363. /*
  364.     Find and return the next event with the lowest time value.
  365.     Return NULL if no more.
  366. */
  367. Cedule * NextCedule()
  368.     {
  369.     Cedule * ced, * next;
  370.     long lowTime;
  371.     int type, vc;
  372.  
  373.     ced = &cedList[ 0][ 0];
  374.     next = NULL;
  375.     lowTime = 0x7fffffff;
  376.     for( type = 0; type < NR_TYPES; type++)
  377.         for( vc = 0; vc < NR_VOICES; vc++, ced++) {
  378.             if( ! ced->used)
  379.                 continue;
  380.             if( ced->rollTime < lowTime) {
  381.                 lowTime = ced->rollTime;
  382.                 next = ced;
  383.                 }
  384.             }
  385.     return next;
  386.     }    /* NextCedule() */
  387.  
  388.  
  389. /*
  390.     Insert in the schedule list the note starting at position
  391.     'pos' of the .ROL note list of voice 'voice'
  392. */
  393. CeduleNoteOn( voice, pos)
  394.     {
  395.     unsigned size;
  396.     Cedule * ced;
  397.     ListDesc * lD;
  398.     NoteEvent * nE;
  399.  
  400.     ced = &cedList[ NOTE_ON_TP][ voice];
  401.     lD = ¬eList[ voice];
  402.     size = lD->size;
  403.     ced->used = 0;
  404.     nE = (NoteEvent *) *lD->liste + pos;
  405.     while( nE->note == 0 && pos < size) {
  406.         /* silences are notes of pitch == 0, and must be skiped */
  407.         offTime[ voice] += nE->duree;
  408.         nE++;
  409.         pos++;
  410.         }
  411.     if( pos < size) {
  412.         ced->rollPos = pos;
  413.         ced->rollTime = offTime[ voice];
  414.         ced->used = 1;
  415.         offTime[ voice] += nE->duree;
  416.         }
  417.     }    /* CeduleNoteOn() */
  418.  
  419.  
  420. CeduleNoteOff( voice, pos)
  421.     {
  422.     Cedule * ced;
  423.  
  424.     ced = &cedList[ NOTE_OFF_TP][ voice];
  425.     ced->rollTime = offTime[ voice];
  426.     ced->rollPos = pos;
  427.     ced->used = 1;
  428.     }    /* CeduleNoteOff() */
  429.  
  430.  
  431.  
  432. CedulePreset( voice, pos)
  433.     {
  434.     Cedule * ced;
  435.     InstrumEvent * iE;
  436.  
  437.     if( NoteSize( voice) == 0)
  438.         return;
  439.     ced = &cedList[ PRESET_TP][ voice];
  440.     if( pos >= InstrumSize( voice))
  441.         ced->used = 0;
  442.     else {
  443.         iE = InstrumAtPos( voice, pos);
  444.         ced->rollTime = iE->time;
  445.         ced->rollPos = pos;
  446.         ced->used = 1;
  447.         }
  448.     }    /* CedulePreset() */
  449.  
  450.  
  451. CedulePitch( voice, pos)
  452.     {
  453.     Cedule * ced;
  454.     PitchEvent * pE;
  455.  
  456.     if( NoteSize( voice) == 0)
  457.         return;
  458.     ced = &cedList[ PITCH_TP][ voice];
  459.     if( pos >= PitchSize( voice))
  460.         ced->used = 0;
  461.     else {
  462.         pE = PitchAtPos( voice, pos);
  463.         ced->rollPos = pos;
  464.         ced->rollTime = pE->time;
  465.         ced->used = 1;
  466.         }
  467.     }    /* CedulePitch() */
  468.  
  469.  
  470. CeduleVolume( voice, pos)
  471.     {
  472.     Cedule * ced;
  473.     VolumeEvent * vE;
  474.  
  475.     if( NoteSize( voice) == 0)
  476.         return;
  477.     ced = &cedList[ VOLUME_TP][ voice];
  478.     if( pos >= VolumeSize( voice))
  479.         ced->used = 0;
  480.     else {
  481.         vE = VolumeAtPos( voice, pos);
  482.         ced->rollPos = pos;
  483.         ced->rollTime = vE->time;
  484.         ced->used = 1;
  485.         }
  486.     }    /* CeduleVolume() */
  487.  
  488.  
  489. CeduleTempo( pos)
  490.     {
  491.     Cedule * ced;
  492.     TempoEvent * tE;
  493.  
  494.     ced = &cedList[ TEMPO_TP][ 0];
  495.     if( pos >= TempoSize())
  496.         ced->used = 0;
  497.     else {
  498.         tE = TempoAtPos( pos);
  499.         ced->rollPos = pos;
  500.         ced->rollTime = tE->time;
  501.         ced->used = 1;
  502.         }
  503.     }    /* CeduleTempo() */
  504.  
  505.  
  506.  
  507.  
  508. /*
  509.     In the normal sequencing order, a note-on must be done
  510.     on the voice & note specified by 'ced'.
  511.  
  512.     Note-on command: <timing> <9n> <pitch> <volume>
  513.     where 'n' is the voice number.
  514. */
  515. DoNoteOn( ced)
  516.     Cedule * ced;
  517.     {
  518.     NoteEvent * nE;
  519.     unsigned vol;
  520.  
  521.     DoTiming( ced);
  522.     DoStatus( ced);
  523.     nE = NoteAtPos( ced->voice, ced->rollPos);
  524.     DoData( nE->note);
  525.     vol = max( 1, voiceVolume[ ced->voice]);
  526.     DoData( vol);
  527.  
  528.     /* schedule the note-off of this note: */
  529.     CeduleNoteOff( ced->voice, ced->rollPos);
  530.  
  531.     /* schedule the next note-on for this voice: */
  532.     CeduleNoteOn( ced->voice, ced->rollPos +1);
  533.     }    /* DoNoteOn() */
  534.  
  535.  
  536. /*
  537.     Note-off command: <timing> <9n> <pitch> <00>
  538.     where 'n' is the voice number.
  539. */
  540. DoNoteOff( ced)
  541.     Cedule * ced;
  542.     {
  543.     NoteEvent * nE;
  544.  
  545.     DoTiming( ced);
  546.     DoStatus( ced);
  547.     nE = NoteAtPos( ced->voice, ced->rollPos);
  548.     DoData( nE->note);
  549.     DoData( 0);
  550.     ced->used = 0;
  551.     }    /* DoNoteOff() */
  552.  
  553.  
  554. /*
  555.     Pitch command: <timing> <En> <pitch-low> <pitch-high>
  556.     where 'n' is the voice number.
  557. */
  558. DoPitch( ced)
  559.     Cedule * ced;
  560.     {
  561.     PitchEvent * pE;
  562.     unsigned uPitch;
  563.  
  564.     DoTiming( ced);
  565.     DoStatus( ced);
  566.     pE = PitchAtPos( ced->voice, ced->rollPos);
  567.     uPitch = pE->pitch * MID_PITCH;
  568.     uPitch = min( MAX_PITCH, uPitch);
  569.     DoData( uPitch);
  570.     DoData( uPitch >> 7);
  571.     CedulePitch( ced->voice, ced->rollPos +1);
  572.     }    /* DoPitch() */
  573.  
  574.  
  575. /*
  576.     After touch command: <timing> <An> <volume>
  577.     where 'n' is the voice number.
  578. */
  579. DoVolume( ced)
  580.     Cedule * ced;
  581.     {
  582.     VolumeEvent * vE;
  583.     NoteEvent * nE;
  584.     Cedule * nCed;
  585.     unsigned volume;
  586.  
  587.     vE = VolumeAtPos( ced->voice, ced->rollPos);
  588.     volume = vE->volume * MAX_VOLUME;
  589.     nCed = &cedList[ NOTE_ON_TP][ ced->voice];
  590.     if( nCed->used && nCed->rollTime == ced->rollTime) {
  591.         /* velocity (volume) is occuring in the same time than a note-on
  592.             on this voice; it will be sent with the note-on itself. ... */
  593.         ;
  594.         }
  595.     else {
  596.         DoTiming( ced);
  597.         DoStatus( ced);
  598.         DoData( volume);
  599.         }
  600.     voiceVolume[ ced->voice] = volume;
  601.     CeduleVolume( ced->voice, ced->rollPos +1);
  602.     }    /* DoVolume() */
  603.  
  604.  
  605. /*
  606.     Preset change command: <timing> <Cn> <preset>
  607.     where 'n' is the voice number.
  608. */
  609. DoPreset( ced)
  610.     Cedule * ced;
  611.     {
  612.     InstrumEvent * iE;
  613.  
  614.     DoTiming( ced);
  615.     DoStatus( ced);
  616.     iE = InstrumAtPos( ced->voice, ced->rollPos);
  617.     DoData( iE->timbreIndex);
  618.     CedulePreset( ced->voice, ced->rollPos +1);
  619.     }    /* DoPreset() */
  620.  
  621.  
  622. /*
  623.     Tempo:  <timing> <F0> <7F> <00> <integer> <frac> <F7>
  624.     (non standard)
  625. */
  626. DoTempo( ced)
  627.     Cedule * ced;
  628.     {
  629.     TempoEvent * tE;
  630.     unsigned ent, frac;
  631.  
  632.     tE = TempoAtPos( ced->rollPos);
  633.     ent = min( (unsigned)tE->tempo, 127);
  634.     frac = (tE->tempo - ent) * 128;
  635.     DoTiming( ced);
  636.     PutByte( SYSTEM_XOR_BYTE);
  637.     status = 0;                     /* status must be re-sent next time */
  638.     PutByte( ADLIB_CTRL_BYTE);
  639.     PutByte( TEMPO_CTRL_BYTE);
  640.     DoData( ent);
  641.     DoData( frac);
  642.     PutByte( EOX_BYTE);
  643.     CeduleTempo( ced->rollPos +1);
  644.     }    /* DoTempo() */
  645.  
  646.  
  647. /*
  648.     End melody: <timing> <FC>
  649. */
  650. DoEndMelo()
  651.     {
  652.     commCount++;
  653.     PutByte( 0);
  654.     PutByte( STOP_BYTE);
  655.     }    /* DoEndMelo() */
  656.  
  657.  
  658.  
  659. /*
  660.     Add the timing bytes. If the delay ( in "n/destTickBeat" Beats)
  661.     is greater than or equal to OVERFLOW, insert enough overflow bytes
  662.     before the timing byte.
  663. */
  664. DoTiming( ced)
  665.     Cedule * ced;
  666.     {
  667.     long    time;
  668.  
  669.     commCount++;
  670.     time = ConvertTime( ced->rollTime);
  671.     while( time - OVERFLOW >= mpuTime) {
  672.         commCount++;
  673.         PutByte( OVERFLOW_BYTE);
  674.         mpuTime += OVERFLOW;
  675.         }
  676.     PutByte( time - mpuTime);
  677.     mpuTime = time;
  678.     }    /* DoTiming() */
  679.  
  680.  
  681. /*
  682.     Convert the time 'rollTime' from the base 'srcTickBeat' (.ROL) to
  683.     the base 'destTickBeat' ( .MUS)
  684. */
  685. long ConvertTime( rollTime)
  686.     Time rollTime;
  687.     {
  688.     long time;
  689.  
  690.     time = (long)rollTime * destTickBeat;
  691.     time /= srcTickBeat;
  692.     return time;
  693.     }    /* ConverTime() */
  694.  
  695.  
  696. /*
  697.     Generate a status byte for the NOTE-ON, NOTE-OFF, PRESET-CHANGE, PITCH-BEND
  698.     or AFTER-TOUCH (volume) midi command.
  699. */
  700. DoStatus( ced)
  701.     Cedule * ced;
  702.     {
  703.     char newStatus;
  704.  
  705.     newStatus = statusArray[ ced->type] + ced->voice;
  706.     if( newStatus != status) {
  707.         status = newStatus;
  708.         PutByte( status);
  709.         }
  710.     }    /* DoStatus() */
  711.  
  712.  
  713. /*
  714.     Send data byte (high bit set to 0) to output file.
  715. */
  716. DoData( data)
  717.     char data;
  718.     {
  719.     PutByte( data & 0x7f);
  720.     }    /* DoData() */
  721.  
  722.  
  723. /*
  724.     Send byte to output file, increment byte counter.
  725. */
  726. PutByte( data)
  727.     char data;
  728.     {
  729.     write( outFile, &data, 1);
  730.     byteCount++;
  731.     }    /* PutByte() */
  732.  
  733.  
  734.  
  735.  
  736.  
  737. /*
  738. -------------------------------------------------------------
  739.     The following routines are used to load a .ROL file in memory.
  740.     Allocate memory using the routines in the MEMORY.C file.
  741. -------------------------------------------------------------
  742. */
  743.  
  744.  
  745. SizeList( liste, nrElems, sizeElem)
  746.     ListDesc * liste;
  747.     unsigned nrElems;
  748.     unsigned sizeElem;
  749. {
  750.     unsigned newSize;
  751.  
  752.     newSize = nrElems * sizeElem;
  753.     if( newSize > liste->nrBytes) {
  754.         newSize = ( newSize + BLOCK_SIZE) & ( ~ (BLOCK_SIZE -1));
  755.         SetHandleSize( liste->liste, (Size)newSize);
  756.         if( MemError())
  757.             SysErr( MemError(), 0);
  758.         liste->nrBytes = newSize;
  759.         }
  760.     liste->size = nrElems;
  761. }    /* SizeListe() */
  762.  
  763.  
  764. SysErr( err, type)
  765.     {
  766.     fprintf( stderr, "\nMemory allocation error, code= %d", err);
  767.     exit( 1);
  768.     }
  769.  
  770.  
  771.     
  772. SizeTempo( size)
  773. {
  774.     SizeList( &tempoList, size, sizeof( TempoEvent));
  775. }    /* SizeTempo() */
  776.  
  777. SizePitch( voice, size)
  778. {
  779.     SizeList( &pitchList[ voice], size, sizeof( PitchEvent));
  780. }    /* SizePitch() */
  781.  
  782. SizeInstrum( voice, size)
  783. {
  784.     SizeList( &instrumList[ voice], size, sizeof( InstrumEvent));
  785. }    /* SizeInstrum() */
  786.  
  787. SizeVolume( voice, size)
  788. {
  789.     SizeList( &volumeList[ voice], size, sizeof( VolumeEvent));
  790. }    /* SizeVolume() */
  791.  
  792. SizeNote( voice, size)
  793. {
  794.     SizeList( ¬eList[ voice], size, sizeof( NoteEvent));
  795. }    /* SizeNote() */
  796.  
  797. SizeTimbre( size)
  798. {
  799.     SizeList( &timbreList, size, sizeof( TimbreDef));
  800. }    /* SizeTimbre() */
  801.  
  802.  
  803.  
  804. TempoEvent * TempoPtr( pos)
  805. {
  806.     return ( TempoEvent *) *tempoList.liste + pos;
  807. }    /* TempoPtr() */
  808.  
  809. VolumeEvent * VolumePtr( voice, pos)
  810. {
  811.     return ( VolumeEvent *) *volumeList[ voice].liste + pos;
  812. }    /* VolumePtr() */
  813.  
  814. PitchEvent * PitchPtr( voice, pos)
  815. {
  816.     return ( PitchEvent *) *pitchList[ voice].liste + pos;
  817. }    /* PitchPtr() */
  818.  
  819. InstrumEvent * InstrumPtr( voice, pos)
  820. {
  821.     return ( InstrumEvent *) *instrumList[ voice].liste + pos;
  822. }    /* InstrumPtr() */
  823.  
  824. NoteEvent  * NotePtr( voice, pos)
  825. {
  826.     return ( NoteEvent *) *noteList[ voice].liste + pos;
  827. }    /* NotePtr() */
  828.  
  829. TimbreDef * TimbrePtr( pos)
  830. {
  831.     return ( TimbreDef *) *timbreList.liste + pos;
  832. }    /* TimbrePtr() */
  833.  
  834.  
  835.  
  836.  
  837. int MyLoadMelo( fileName)
  838.     char * fileName;
  839. {
  840.     int fileId, i;
  841.     char buffer[ 255];
  842.  
  843.     pitchBRange = 1;
  844.  
  845.     strcpy( buffer, fileName);
  846. /*    strcat( buffer, musicFileExtension);    */
  847.     fileId = open( buffer, O_RDONLY + O_RAW);
  848.     if( fileId == -1)
  849.         return 0;
  850.  
  851.     duree_piece = 0;
  852.  
  853.     if( 4 != read( fileId, buffer, 4))    /* skip file version, major & minor */
  854.         return 0;
  855.     if( 40 != read( fileId, buffer, 40))    /* skip filler field */
  856.         return 0;
  857.     if( 2 != read( fileId, &srcTickBeat, 2))
  858.         return 0;
  859.     if( 2 != read( fileId, &beatMeasure, 2))
  860.         return 0;
  861.     if( 5 != read( fileId, buffer, 5))    /* skip Y scale, X scale & filer */
  862.         return 0;
  863.     if( 1 != read( fileId, ¬PercusMode, 1))
  864.         return 0;
  865.     if( (90 + 38 + 15) != read( fileId, buffer, 90 + 38 + 15))
  866.         return 0;                    /* skip 3 filler field */
  867.     if( 4 != read( fileId, &basicTempo, 4))
  868.         return 0;
  869.     if( ! LoadTempo( fileId))
  870.         return 0;
  871.  
  872.     for( i = 0; i < NR_VOICES; i++) {
  873.         if( 15 != read( fileId, buffer, 15))    /* skip filler */
  874.             return 0;
  875.         if( ! LoadNotes( fileId, i))
  876.             return 0;
  877.         if( 15 != read( fileId, buffer, 15))
  878.             return 0;
  879.         if( ! LoadInstrumEvt( fileId, i))
  880.             return 0;
  881.         if( 15 != read( fileId, buffer, 15))
  882.             return 0;
  883.         if( ! LoadVolume( fileId, i))
  884.             return 0;
  885.         if( 15 != read( fileId, buffer, 15))
  886.             return 0;
  887.         if( ! LoadPitch( fileId, i))
  888.             return 0;
  889.         }
  890.     LisMidiData( fileId);
  891.     close( fileId);
  892.     return 1;
  893. }    /* MyLoadMelo() */
  894.  
  895.  
  896.  
  897. int LoadPitch( fileId, voice)
  898. {
  899.     int size, i, ok;
  900.     PitchEvent * pEvent;
  901.  
  902.     if( 2 != read( fileId, &size, 2))
  903.         return 0;
  904.     SizePitch( voice, size);
  905.     pEvent = PitchPtr( voice, 0);
  906.     ok = 1;
  907.     for( i = 0; i < size && ok; i++, pEvent++)
  908.         ok = ( 6 == read( fileId, pEvent, 6));
  909.     return ok;
  910. }    /* LoadPitch() */
  911.  
  912.  
  913. int LoadVolume( fileId, voice)
  914. {
  915.     int size, i, ok;
  916.     VolumeEvent * vEvent;
  917.  
  918.     if( 2 != read( fileId, &size, 2))
  919.         return 0;
  920.     SizeVolume( voice, size);
  921.     vEvent = VolumePtr( voice, 0);
  922.     ok = 1;
  923.     for( i = 0; i < size && ok; i++, vEvent++) {
  924.         ok = ( 6 == read( fileId, vEvent, 6));
  925.         }
  926.     return ok;
  927. }    /* LoadVolume() */
  928.     
  929.  
  930.  
  931.  
  932. int LoadInstrumEvt( fileId, voice)
  933. {
  934.     int size, ok, i;
  935.     InstrumEvent * iEvent;
  936.  
  937.     if( 2 != read( fileId, &size, 2))
  938.         return 0;
  939.     ok = 1;
  940.     SizeInstrum( voice, size);
  941.     iEvent = InstrumPtr( voice, 0);
  942.     for( i = 0; i < size && ok; i++, iEvent++)
  943.         ok = ( 14 == read( fileId, iEvent, 14));
  944.     return ok;
  945. }    /* LoadInstrumEvt() */
  946.  
  947.                 
  948.  
  949.  
  950. int LoadNotes( fileId, voice)
  951. {
  952.     NoteEvent * nEvent;
  953.     Time time, lastTime;
  954.     int count, ok;
  955.  
  956.     time = 0;
  957.     if( 2 != read( fileId, &lastTime, 2))
  958.         return 0;
  959.     ok = 1;
  960.     count = 0;
  961.     SizeNote( voice, count);
  962.     while( time < lastTime && ok ) {
  963.         SizeNote( voice, count + 1);
  964.         nEvent = NotePtr( voice, count);
  965.         count++;
  966.         ok = ( 4 == read( fileId, nEvent, 4));
  967.         time += nEvent->duree;
  968.         }
  969.     duree_piece = max( duree_piece, lastTime);
  970.     return ok;
  971. }    /* LoadNotes() */
  972.  
  973.  
  974.     
  975.  
  976.  
  977.  
  978. int LoadTempo( fileId)
  979. {
  980.     int size, i, ok;
  981.     TempoEvent * tEvent;
  982.  
  983.     if( 2 != read( fileId, &size, 2))
  984.         return 0;
  985.     
  986.     SizeTempo( size);
  987.     tEvent = TempoPtr( 0);
  988.     ok = 1;
  989.     for( i = 0; i < size && ok; i++, tEvent++) {
  990.         ok = ( 6 == read( fileId, tEvent, 6));
  991.         }
  992.     return ok;
  993. }    /* LoadTempo() */
  994.  
  995.     
  996.  
  997. /*
  998.     If the .ROL file was written by the "Visual Composer/MIDI Supplement",
  999.     the pitch bend range is read from the file.
  1000. */
  1001. LisMidiData( fileId)
  1002.     {
  1003.     struct midi_vars midiParam;
  1004.     int i;
  1005.     
  1006.     midiParam.midiVersion_ = 0;
  1007.     read( fileId, &midiParam, sizeof( struct midi_vars));
  1008.     if( midiParam.midiVersion_) {
  1009.         /* le fichier contient le data MIDI ... */
  1010.         pitchBRange = midiParam.pitchRange_;
  1011.         }
  1012.     }    /* LisMidiData() */
  1013.  
  1014.  
  1015. /*
  1016.     For each timbre reference in the .ROL file, search the index
  1017.     of the bank file (.SND) for the timbre.  If it exists, get the relative
  1018.     position of the definition, if not, search in the current directory for
  1019.     the timbre, and add it to the end of the bank file. The relative position
  1020.     is the value saved with the command PROGRAM-CHANGE in the .MUS file.
  1021.  
  1022.     If the timbre is not found, a warning message is printed on the screen,
  1023.     and the timbre reference value is set to 0 ( first timbre of bank).
  1024. */
  1025. LoadTimbres()
  1026. {
  1027.     int voice, j, k, ok, nrDefs, fileId, timbPos;
  1028.     int timbreDef[ TIMBRE_DEF_LEN];
  1029.     InstrumEvent * iEvent;
  1030.     char fileN[ 80];
  1031.     char buff[ 10];
  1032.  
  1033.     for( voice = 0; voice < NR_VOICES; voice++) {
  1034.         iEvent = InstrumPtr( voice, 0);
  1035.         for( j = instrumList[ voice].size; j; j--, iEvent++) {
  1036.             iEvent->timbreIndex = 0;    /* the first, by default */
  1037.  
  1038.             if( GetTimbre( iEvent->instrumName, &timbPos, timbreDef, timbBank))
  1039.                 iEvent->timbreIndex = timbPos;
  1040.             else {
  1041.                 setmem( timbreDef, TIMBRE_DEF_SIZE, 0);
  1042.                 strcpy( fileN, iEvent->instrumName);    
  1043.                 strcat( fileN, instrumFileExtension);
  1044.                 fileId = open( fileN, O_RDONLY + O_RAW);
  1045.                 if( fileId != -1) {
  1046.                     read( fileId, buff, 2);        /* skip instrum header */
  1047.                     read( fileId, timbreDef, TIMBRE_DEF_SIZE);
  1048.                     close( fileId);
  1049.                     AddTimbre( iEvent->instrumName, &timbPos, timbreDef, timbBank);
  1050.                     iEvent->timbreIndex = timbPos;
  1051.                     }
  1052.                 else {
  1053.                     fprintf( stderr, "\nInstrument not found: %s", fileN);
  1054.                     }
  1055.                 }
  1056.             }
  1057.         }
  1058. }    /* LoadTimbres() */
  1059.  
  1060.  
  1061.  
  1062.  
  1063.  
  1064.  
  1065.  
  1066.